import gc
import datetime

from bases.ui_modules import gtk

from Bases import BaseObject
from Bases.tempo import TapTempo
from ui_base.gtk.gtkBaseUI import BaseWindow
from bases import widgets

from devicetree import DeviceTree

from views import view_classes

from osc_tree import OSCTree

class MainWindow(BaseWindow):
    #topwidget_name = 'main'
    window_size = [1150, 800]
    #_Properties = {'fullscreen':dict(default=False)}
    def __init__(self, **kwargs):
        super(MainWindow, self).__init__(**kwargs)
        self.MainController = kwargs.get('MainController')
        self.DeviceSystem = self.MainController.DeviceSystem
        self.FileManager = self.MainController.FileManager
        self.comm = self.MainController.comm
        
        self.current_view = None
        self.current_filename = None
        
        self.topwidget = self.make_child_widget(widgets.VBox, 'topwidget')
        
        menu_info = {'File':['New', 'Open', 'Save', 'Save As', 'Save Globals', 'Recent', 'Exit'], 
                     'Windows':['Attributes', 'Definitions', 'Patch', 'Devices', 'Cue Stack'], 
                     'Setup':['Universes', 'OSC', 'Communication']}
        self.menu = self.make_child_widget(widgets.MenuBar, 'menu',
                                           menu_info=menu_info, 
                                           menu_order=('File', 'Windows', 'Setup'))
        self.recent_manager = gtk.RecentManager()#.get_default()
        self.recent_chooser = gtk.RecentChooserMenu()
        #self.recent_chooser.set_property('recent-manager', self.recent_manager)
        self.recent_chooser.set_show_private(True)
        for filetype in self.FileManager.filetypes.itervalues():
            if not len(filetype.mimetype):
                continue
            filter = gtk.RecentFilter()
            filter.set_name(filetype.description)
            filter.add_mime_type(filetype.mimetype)
            self.recent_chooser.add_filter(filter)
        self.recent_chooser.connect('item-activated', self.on_recent_item_activated)
        #items = self.recent_chooser.get_items()
        #for item in items:
        #    print item.get_display_name(), item.get_applications()
        #self.menu.menus['File'].items['Recent'].set_submenu(self.recent_chooser)
        
        self.topwidget.pack_start(self.menu, expand=False, fill=False)#, padding=2)
        
        d = {'New':['File', 'New'], 
             'Open':['File', 'Open'], 
             'Save':['File', 'Save'], 
             'Save As':['File', 'Save As'], 
             'Save Globals':['File', 'Save Globals'], 
             'Attributes':['Windows', 'Attributes'], 
             'Definitions':['Windows', 'Definitions'], 
             'Patch':['Windows', 'Patch'], 
             'Devices':['Windows', 'Devices'], 
             'Universes':['Setup', 'Universes'], 
             'Cue Stack':['Windows', 'Cue Stack'], 
             'Communication':['Setup', 'Communication']}
        for key, val in d.iteritems():
            self.menu.menus[val[0]].items[val[1]]._item.connect('activate', self.on_menuitem_activate, key)
        
        #box = self.make_child_widget(widgets.HBox, 'hbox1')
        box = self.make_child_widget(widgets.HBox, 'hbox1')
        
        btn = self.make_child_widget(gtk.ToggleButton, 'btnConnect', label='Connect')
        btn.connect('clicked', self.on_btnConnect_clicked)
        box.pack_start(btn)
        
        btn = self.make_child_widget(gtk.Button, 'btnTest', label='Test')
        btn.connect('clicked', self.on_btnTest_clicked)
        box.pack_start(btn)
        
        for key in self.MainController.EffectsSystem.Macros.iterkeys():
            btn = widgets.Button(label=key)
            btn.connect('clicked', self.on_macro_btn_clicked, key)
            box.pack_start(btn)
            
        vbox = widgets.VBox()
        btn = widgets.Button(label='Tap')
        btn.connect('clicked', self.on_btn_tap_clicked)
        self.lbl_tempo = widgets.Label()
        vbox.pack_start(btn)
        vbox.pack_start(self.lbl_tempo)
        box.pack_start(vbox)
        #self.taptempo = TapTempo()
        #self.taptempo.bind(tempo=self.on_tempo_change)
#        clockvb = widgets.VBox()
#        self.clock_label = widgets.Label()
#        clockvb.pack_start(self.clock_label)
#        
#        self.tick_label = widgets.Label()
#        clockvb.pack_start(self.tick_label)
#        
#        self.offset_label = widgets.Label()
#        clockvb.pack_start(self.offset_label)
#        
#        box.pack_start(clockvb)
#        self.MainController.EffectsSystem.clock.add_callback(self.on_clock_interval)
        
        self.fullscreen_toggle = widgets.ToggleBtn(label='Fullscreen', Property=(self, 'fullscreen'))
        box.pack_end(self.fullscreen_toggle.widget)
        
        self.topwidget.pack_start(box)
        self.Pane = ViewPane(MainController=self.MainController, position=self.window_size[0] / 2)
        self.topwidget.pack_start(self.Pane.topwidget, expand=True)
        self.window.add(self.topwidget)
        self.window.show_all()
        
        #self.bind(fullscreen=self._on_fullscreen_set)
    def on_btn_tap_clicked(self, btn):
        self.taptempo.tap = True
    def on_tempo_change(self, **kwargs):
        value = kwargs.get('value')
        self.lbl_tempo.set_text('%06.3f bpm' % (value))
    def build_view(self, key):
        cls = view_classes.get(key)
        if cls is not None:
            if self.current_view is not None:
                self.current_view.unlink()
                self.topwidget.remove(self.current_view.topwidget)
            self.current_view = cls(MainController=self.MainController)
            self.topwidget.pack_start(self.current_view.topwidget, expand=True)
        
#    def on_clock_interval(self, clock, seconds):
#        #self.clock_label.set_text('%010.6f' % (seconds))
#        #self.tick_label.set_text('%010.6f' % (clock.clock_seconds))
#        #self.offset_label.set_text('%010.6f' % (clock.clock_seconds - seconds))
#        midi = self.comm.midi_io
#        realsec = midi.datetime_to_module_time(datetime.datetime.now()) / midi.time_scale
#        midisec = midi.get_module_time() / midi.time_scale
#        offset = midi.module_time_offset
#        self.clock_label.set_text('%010.6f' % (realsec))
#        self.tick_label.set_text('%010.6f' % (midisec))
#        self.offset_label.set_text('%010.6f' % (offset))
        
        
    def on_menuitem_activate(self, menuitem, key):
        if key in view_classes:
            self.build_view(key)
        elif key == 'New':
            self.FileManager.close_file()
        elif key == 'Open':
            self.do_file_open()
        elif key == 'Save':
            self.do_file_save()
        elif key == 'Save As':
            self.do_file_save_as()
        elif key == 'Save Globals':
            self.do_file_save_globals()
    
    def on_btnConnect_clicked(self, btn):
        if self.comm.connected:
            self.comm.do_disconnect()
        else:
            self.comm.do_connect()
            
            
    def on_macro_btn_clicked(self, btn, key):
        macro = self.MainController.EffectsSystem.Macros[key]
        macro.run()
            
    def on_btnTest_clicked(self, btn):
        before = gc.get_count()
        r = gc.collect()
        self.LOG.debug('collected=%s, before=%s, after=%s, garbage=%s' % (r, before, gc.get_count(), gc.garbage))
    
    def show_file_dialog(self, **kwargs):
        def custom_filter(info, key):
            if type(info) == tuple:
                class Info(object):
                    def __init__(self, info):
                        for key, val in zip(['filename', 'uri', 'display_name', 'mime_type'], info):
                            setattr(self, key, val)
                info = Info(info)
            filetype = self.FileManager.guess_filetype(info.filename)
            if filetype is None:
                return False
            return filetype.id == key
        filter = kwargs.get('default_filter')
        if 'filename' not in kwargs:
            folder = self.FileManager.most_recent_dir
            if folder is not None:
                if 'file://' not in folder:
                    folder = 'file://' + folder
                kwargs.setdefault('current_folder', folder)
        kwargs['filters'] = {'all':[['pattern', '*']]}
        for key, val in self.FileManager.filetypes.iteritems():
            #if True:#len(val.mimetype):
            #    args = ['mime', val.mimetype]
            #else:
            #    args = ['pattern', '*' + val.extension]
            args = [['custom', custom_filter, val.id]]
            kwargs['filters'][val.description] = args
        if filter is None:
            ft = self.FileManager.default_filetype
            if ft is not None:
                kwargs['default_filter'] = ft.description
        file_dialog = widgets.FileDialog(**kwargs)
        
        response = file_dialog.show()
        return response
    
    def do_file_open(self, **kwargs):
        response = self.show_file_dialog(mode='open', label='Open')
        if response['response']:
            #self.DeviceSystem.from_json(filename=response['filename'])
            self.FileManager.load_file(filename=response['filename'])
            #gtk.recent_manager_get_default().add_item(response['uri'])
            self.add_recentmanager_item(response['uri'])
            self.current_filename = response['filename']
        
    def do_file_save(self, **kwargs):
        #filename = kwargs.get('filename', self.current_filename)
        #uri = kwargs.get('uri')
        #self.MainController.save_file(filename=filename, json_preset='pretty')
        if not self.FileManager.save_current():
            self.do_file_save_as()
        
    def do_file_save_as(self, *args):
        dlg_kwargs = dict(mode='save', label='Save As')
        current = self.FileManager.current_file
        if current is not None:
            dlg_kwargs['filename'] = current
        else:
            ft = self.FileManager.default_filetype
            if ft is not None:
                dlg_kwargs['current_name'] = 'Untitled'+ft.extension
        response = self.show_file_dialog(**dlg_kwargs)
        if response['response']:
            #self.do_file_save(**response)
            self.FileManager.save_file(filename=response['filename'])
            #gtk.recent_manager_get_default().add_item('file://'+response['filename'])
            self.add_recentmanager_item('file://'+response['filename'])
            self.current_filename = response['filename']
        
    def add_recentmanager_item(self, uri):
        filetype = self.FileManager.guess_filetype(uri.split('file://')[1])
        if filetype is None:
            return
        #rm = gtk.recent_manager_get_default()
        d = dict(mime_type=filetype.mimetype, 
                 app_name=self.GLOBAL_CONFIG['app_name'], 
                 app_exec='', 
                 groups=[], 
                 is_private=True)
        #keys = ['display_name', 'description', 'mime_type', 'app_name', 'app_exec', 'groups', 'is_private']
        #args = [d.get(key) for key in keys]
        #rdata = gtk.RecentData(*args)
        #self.recent_manager.add_full(uri, rdata)
        self.recent_manager.add_item(uri)
            
    def on_recent_item_activated(self, chooser):
        uri = chooser.get_current_uri()
        filename = uri.split('file://')[1]
        self.FileManager.load_file(filename=filename)
        self.current_filename = filename

    def do_file_save_globals(self, *args):
        self.MainController.save_globals()
    
class ViewPane(BaseObject):
    pane_classes = {'vertical':widgets.VPane, 'horizontal':widgets.HPane}
    def __init__(self, **kwargs):
        super(ViewPane, self).__init__(**kwargs)
        self.MainController = kwargs.get('MainController')
        orientation = kwargs.get('orientation', 'horizontal')
        self.topwidget = self.pane_classes.get(orientation)()
        pos = kwargs.get('position')
        if pos:
            self.position = pos
        self.panels = []
        for x in range(2):
            p = SubPanel(MainController=self.MainController)
            self.topwidget.pack_start(p.topwidget, expand=True)
            self.panels.append(p)
        self.topwidget.show_all()
        
    def unlink(self):
        for p in self.panels:
            p.unlink()
    @property
    def position(self):
        return self.topwidget.get_position()
    @position.setter
    def position(self, value):
        self.topwidget.set_position(value)
        
class SubPanel(BaseObject):
    def __init__(self, **kwargs):
        super(SubPanel, self).__init__(**kwargs)
        self.MainController = kwargs.get('MainController')
        self.topwidget = widgets.Frame()
        self.current_view = None
        self.tophbox = widgets.HBox()
        self.view_combo = widgets.Combo(no_frame=True)
        for key in view_classes.iterkeys():
            self.view_combo.update({key:key})
        self.view_combo.connect('selection_changed', self.on_view_selection_changed)
        self.tophbox.pack_start(self.view_combo.topwidget, expand=True)
        self.splitbtns = {}
        for key, name in zip(['horizontal', 'vertical'], ['Split Horizontally', 'Split Vertically']):
            btn = widgets.Button(label=name)
            btn.connect('clicked', self.on_split_btn_clicked, key)
            self.tophbox.pack_end(btn, expand=False, fill=False)
            self.splitbtns[key] = btn
        self.topwidget.pack_start(self.tophbox, expand=False)
        self.unsplit_btn = widgets.Button(label='Unsplit')
        self.unsplit_btn.connect('clicked', self.on_unsplit_btn_clicked)
        self.view_container = widgets.ScrolledWindow()
        self.view_combo.set_current_selection(key='Blank')
        self.topwidget.pack_start(self.view_container, expand=True)
        #self.topwidget.show_all()
        
    def unlink(self):
        if self.current_view:
            self.current_view.unlink()
            
    def set_current_view(self, key=None):
        if self.current_view:
            self.current_view.unlink()
            self.view_container.remove(self.current_view.topwidget)
        if key is not None:
            cls = view_classes[key]
            self.current_view = cls(MainController=self.MainController)
            self.view_container.add(self.current_view.topwidget)
            
    def split_panel(self, orientation):
        viewkey = None
        if self.current_view is not None:
            cls = self.current_view.__class__
            for key, val in view_classes.iteritems():
                if cls == val:
                    viewkey = key
                    break
        self.set_current_view(None)
        self.topwidget.remove(self.tophbox)
        self.topwidget.remove(self.view_container)
        self.topwidget.pack_start(self.unsplit_btn)
        if orientation == 'horizontal':
            key = 'width'
        else:
            key = 'height'
        pos = getattr(self.topwidget.get_allocation(), key) / 2
        self.subpane = ViewPane(MainController=self.MainController, orientation=orientation, position=pos)
        self.topwidget.pack_start(self.subpane.topwidget, expand=True)
        self.topwidget.show_all()
        self.subpane.panels[0].set_current_view(viewkey)
        
    def unsplit_panel(self):
        viewkey = None
        if self.subpane.panels[0].current_view is not None:
            cls = self.subpane.panels[0].current_view.__class__
            for key, val in view_classes.iteritems():
                if cls == val:
                    viewkey = key
                    break
        self.subpane.unlink()
        tw = self.topwidget
        tw.remove(self.subpane.topwidget)
        tw.remove(self.unsplit_btn)
        tw.pack_start(self.tophbox)
        tw.pack_start(self.view_container, expand=True)
        tw.show_all()
        self.set_current_view(viewkey)
        
    def on_view_selection_changed(self, **kwargs):
        key = kwargs.get('key')
        self.set_current_view(key)
        
    def on_split_btn_clicked(self, btn, key):
        self.split_panel(key)
        
    def on_unsplit_btn_clicked(self, btn):
        self.unsplit_panel()
